#include "napi/native_api.h"
#include "test_header.h"
#include<iostream>
#include<climits>
#include<cfloat>
#include <exception>
#include "call_file.h"
#include "call_file.cpp"
using namespace std;
using std::cout;
using std::endl;

int global_var1_1 = 0;
static double global_var2_1 = 100;
static double global_var2_1_use = 789;
char global_var3_1 = 'h';

int test_switch (int num) {
    int num_sign = 0;
    switch (num)
    {
        case 10: num_sign = num + 1 ; break;
        case 20: num_sign = num + 2 ; break;
        case 30: num_sign = num + 3 ; break;
        default: num_sign = num + 10 ; break;
    }
    return num_sign;
}

int test_while () {
    int i = 0;
    while(i < 10)
    {
        i = i + 1;
    }
    return 0;
}


int test_dowhile() {
    int i = 1;
    do{
        int j = 1;
        do{
            j++;
        } while (j <= 3) ;
        i++;
    } while (i <= 3) ;
    return 0;
}

void func() {
    static int i=0; //static variable
    int j=0; //local variable
    i++;
    j++;
}

int test_use_func()
{
    func();   //i= 1 and j= 1
    func();   //i= 2 and j= 1
    func();   //i= 3 and j= 1
    return 0;
}

int test_for () {
    int num;
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            num = i + j ;
        }
    }
    return 0;
}

//递归，测试stepin 和调用栈查看
int factorial(int n)
{
    if(n<0)
        return(-1); /*Wrong value*/
    if(n==0)
        return(1);  /*Terminating condition*/
    else
    {
        return(n*factorial(n-1)); //打断点测试stepin/stepout
    }
}

float division(int x, int y) {
    if( y == 0 ) {
        throw "Attempted to divide by zero!";
    }
    return (x/y);
}


int test_try_catch () {
    int i = 25;
    int j = 0;
    float k = 0;
    try {
        k = division(i, j);
    }catch (const char* e) {
        ;
    }
    return 0;
}

// 测试变量查看及修改
int test_var(){
    double setuse = global_var2_1_use;
    int fornu;
    for (int i = 0;i<5;i++){
        fornu = i;
    }
    static int n_static = 1350;
    int n_arry_1[7] = {1,2,3,4,5,6,7};
    double balance[100] = {50.0};
    int int_blank[30] = {};
    long long_blank[31] = {};
    float float_blank[29] = {78.89};
    char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};
    char str_1[] = {'C','+','+','\0'};
    char str_2[4] = {'C','+','+','\0'};
    char str_3[] = "a\0b";
    char str_4[100] = "C++";
    int salary = 85000;
    signed int x = 23;
    unsigned int x2 = 2; //测试修改成负整数是否允许
    char test = 'h';
    signed char  sin_1 = 12; //signed 范围是-127到127，测试正常范围及超范围修改现象
    unsigned char  unsin_1 = -85; //unsigned char的范围是0到255，测试正常范围及超范围修改现象
    float area = 64.74;
    double volume = 134.64534;
    bool cond = false;
    long b = 4523232;
    long int c = 2345342;
    long double d = 233434.56343;
    int n_int=INT_MAX;
    int m_int=INT_MIN;
    long n_long=LONG_MAX;
    long m_long=LONG_MIN;
    short n_short=SHRT_MAX;
    short m_short=SHRT_MIN;
    long long n_llong=LLONG_MAX;
    long long m_llong=LLONG_MIN;
    float n_float=FLT_MAX;
    float m_float=FLT_MIN;
    double n_double=DBL_MAX;
    double m_double=DBL_MIN;
    long double n_ldouble=LDBL_MAX;
    long double m_ldouble=LDBL_MIN;
    short a = 12345;
    return 0;
}

class Student{
private:
    char *m_name;
    int m_age;
    float m_score;
public:
    //声明构造函数
    Student(char *name, int age, float score);
    //声明普通成员函数
    void show();
};

//定义构造函数
Student::Student(char *name, int age, float score){
    m_name = name;
    m_age = age;
    m_score = score;
}

//定义普通成员函数
void Student::show(){
    cout<<m_name<<"的年龄是"<<m_age<<"，成绩是"<<m_score<<endl;
}

int test_class(){
    //创建对象时向构造函数传参
    Student stu((char*)"小明", 15, 92.5); //断点，测试构造函数的stepin
    stu.show(); //断点，测试普通成员函数的stepin

    //创建对象时向构造函数传参
    Student *pstu = new Student((char*)"李华", 16, 96); //断点，测试构造函数的stepin
    pstu -> show(); //断点，测试普通成员函数的stepin
    return 0;
}

double test_division(int a, int b)
{
    if( b == 0 )
    {
        throw "Division by zero condition!";
    }
    return (a/b);
}

void test_catch_division(int x, int y){
    double z = 0;
    try {
        z = test_division(x, y);
    }catch (const char* msg) {
        cerr << msg << endl;
    }
}

struct test_MyException : public exception
{
    const char * what () const throw ()
    {
        return "C++ Exception";
    }
};


static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);
    int a=1;
    int num_switch = test_switch(20);
    test_while();
    test_dowhile();
    test_use_func();
    factorial(10);
    division(10,90);
    test_try_catch ();
    test_var();
    test_class();


    // 设置异常断点，并且异常断点被触发
    test_catch_division(2,0);

    //    // 设置异常断点在test_while中的断点被击中后才有效
    test_while();
    //
    //    // 设置异常断点，并且异常断点被触发
    test_catch_division(2,0);
    //
    //    // 设置异常断点，但是异常断点未被触发
    test_catch_division(2,1);
    //
    //    // 自定义异常类，被触发
    //    test_catch_MyException();


    // 源码断点

    //call_file.cpp
    call_show(100);
//    call_test_try_catch ();
    call_factorial(6);
    call_test_class();

    test_watch();

    return sum;

}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "hello",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterHelloModule(void)
{
    napi_module_register(&demoModule);
}
